#!/usr/bin/env python

""" Get the (possibly virtual) topography of the network: kernel
 objects list and dot graph.

 Requires pywrekamapd.py

 Usage: ./getTopo.py [-f hosts file (--set_list_file)] [-i hosts list
 (--set_list_flat)] [-o dot ouput file (--output)][--hostname use
 hostname] [--address use IP address] [--output] [--graph print graph
 only] [--stats print objects only] [-h help]

 For the wrekagrid project,
 Basile Clout, October 2007"""


import os
import getopt
import pprint
import sys
from datetime import datetime

def getFlat(a):

    mylist = ""
    
    try:
        hostfile = file(a, "r")
    except OSError:
        print "File "+a+" not found"
        sys.exit(2)

    for line in hostfile:
        mylist += line.strip('\n')+" "

    return mylist


def main():


    list_hosts = "lids02 lids04 lids05 lids06 lids09 lids13 lids15 lids16"
    ssh_bin = "ssh"
    log_file = "getTopo.log"
    dot_file = "topo.dot"
    ifn = "eth0"
    switch = 1                          # 0 means ip, 1 means hostname 
    mode = 2                            # 0 means graph, 1 means stat, 2 means both (graph AND stat)
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hf:i:o:", ["set_list_flat=", "set_list_file=", "help=", "hostname", "address", "output=", "graph", "stats"])
    except getopt.error, msg:
        print msg
        print "For help, use --help"
        sys.exit(2)

    for o, a in opts:
        if o in ("-h", "--help"):
            print __doc__
            sys.exit(0)
        elif o in ("-f", "--set_list_file"):
            list_hosts = getFlat(a)
        elif o in ("-i", "--set_list_flat"):
            list_hosts = a
        elif o == "--address":
            switch = 0
        elif o == "--hostname":
            switch = 1
        elif o in ("-o", "--output"):
            dot_file = a
        elif o == "--graph":
            mode = 0
        elif o == "--stats":
            mode = 1
        else:
            print "Not such option "+o
            sys.exit(1)

    try:
        log = open(log_file, "w")
    except OSError:
        print "Impossible to create logfile "+log_file
        sys.exit(2)

    try:
        dot = open(dot_file, "w")
    except OSError:
        print "Impossible to create dot file "+dot
        sys.exit(2)

    log.write("Created on "+str(datetime.now())+" by getTopo.py\n\n") 
    
    daemon_bin = "/root/config/code/tools/pywrekamapd.py"
    daemon_fl = "--net_off --cpu_off --set_list \\\""+list_hosts+"\\\""
    
    
    myhash = {}
    ip2name = {}
    name2ip = {}
    node_arr = list_hosts.split()

    for node in node_arr:

        log.write("@"+node+" \n")
        order = ssh_bin+" "+node+" \""+daemon_bin + " " + daemon_fl+"\""
        log.write("Order: "+order+"\n")
        stdin, stdout, stderr = os.popen3(order)
        output, errput = stdout.read(), stderr.read()
        log.write(output+"\n")

        if mode != 1:
            # First, get topo
            for line in output.splitlines():

                parts = line.split()
                if parts[0] == "node":
                    address = parts[2]
                    hostname = parts[1]
                    name2ip[hostname]=address
                    ip2name[address]=hostname

                    if node not in (hostname, address):
                        print "Error daemon. Interrogate has to be "+node+", not "+parts[1]+"/"+parts[2]
                        sys.exit(2)

                if parts[0] == "neighbors":
                    myhash[hostname] = parts[1:]


        if mode != 0:
            # Second, get stat for qdisc, class, filter and routes
            line = "---------Stats for "+node+"---------------------------------------------------------------------------"
            print line
            log.write(line+"\n")

            line = "---> Main routing table:"
            print line
            log.write(line)
            order = ssh_bin+" "+node+" \"ip route ls\""
            log.write(order)
            stdin, stdout, stderr = os.popen3(order)
            output, errput = stdout.read(), stderr.read()
            print output
            log.write(output+errput)

            line = "---> Queing disciplines:"
            print line
            log.write(line)
            order = ssh_bin+" "+node+" \"tc qdisc show dev "+ifn+" \""
            log.write(order)
            stdin, stdout, stderr = os.popen3(order)
            output, errput = stdout.read(), stderr.read()
            print output
            log.write(output+errput)

            line = "---> Classes:"
            print line
            log.write(line)
            order = ssh_bin+" "+node+" \"tc class show dev "+ifn+" \""
            log.write(order)
            stdin, stdout, stderr = os.popen3(order)
            output, errput = stdout.read(), stderr.read()
            print output
            log.write(output+errput)

            line = "---> Filters:"
            print line
            log.write(line)
            order = ssh_bin+" "+node+" \"tc filter show dev "+ifn+" \""
            log.write(order)
            stdin, stdout, stderr = os.popen3(order)
            output, errput = stdout.read(), stderr.read()
            print output
            log.write(output+errput)


    if mode != 1:        
        # Print dot file
        content = "digraph topo {\n"
        content+= "\toverlap=scale;\n"


        for key, value in myhash.iteritems():

#            print key, " --> ", value
            i = node_arr.index(key)
            if switch == 0:
                content += "\t"+str(i)+" [label=\""+name2ip[key]+"\"];\n"
            else:
                content += "\t"+str(i)+" [label=\""+key+"\"];\n"

            for remote in value:
                content += "\t"+str(i)+" -> "+str(node_arr.index(ip2name[remote]))+";\n"

        content += "}\n"
        log.write(content)
        dot.write(content)
        print dot_file + " written!"

    dot.close()
        
if __name__ == "__main__":
    main()
    
                
        
        




 

